#include "FileUtils.h"
#include <sys/stat.h>
#include "ZipException.h"
#include <string.h>
#include <string>
#include <stdlib.h>
#include <dirent.h>

struct stat st_info;

bool isFile(const char *path)
{

    if(path)
    {
        if(stat(path, &st_info) < 0)
        {
            return false;
        }
    }
    return S_ISREG(st_info.st_mode);
}

bool isDirectory(const char *path)
{
    if(path)
    {
        if(stat(path, &st_info) < 0)
        {
            return false;
        }
    }
    return S_ISDIR(st_info.st_mode);
}

void createDirectory(const char* path)
{

    int createDir = mkdir(path, S_IRWXU | S_IRGRP | S_IXGRP);
    if(createDir < 0)
    {
        throw ZipException("Couldn't create directory");
    }
}

tm * getLastModificationTimeAndDate(const char* path)
{
    struct tm* tmModifiedTime;
    struct stat attrib;
    stat(path, &attrib);
    tmModifiedTime = localtime(&(attrib.st_mtime));
    return tmModifiedTime;
}

char* getSimpleName(const char* path)
{
    string filename = path;
    size_t lastSlashIndex = filename.find_last_of("\\/", filename.size() - 2);
    if(string::npos != lastSlashIndex)
        filename.erase(0, lastSlashIndex + 1);
    char *name = new char[strlen(filename.c_str()) + 1];
    strcpy(name, filename.c_str());
    name[filename.size()] = '\0';
    return name;
}

void createDirectoriesFromPath(const char* path)
{
    int lastSeparatorPos = 0;
    int numberOfSeparators = countNumberOfSeparators(path);
    for(int i = 0; i < numberOfSeparators; i++)
    {
        std::string fullPath = path;
        lastSeparatorPos = fullPath.find_first_of("/", lastSeparatorPos);
        std::string newPath = fullPath.substr(0, lastSeparatorPos + 1);
        if(isDirectory(newPath.c_str()) == false)
            createDirectory(newPath.c_str());
        lastSeparatorPos++;
    }
}

int countNumberOfSeparators(const char* path)
{
    int counter = 0;
    for(int i = 0; i < strlen(path); i++)
    {
        if(path[i] == '/')
            counter++;
    }
    return counter;
}

long getFileContentSize(FILE* file)
{
    fseek(file, 0, SEEK_END);
    long fileSize = ftell(file);
    fseek(file, 0, SEEK_SET);

    return fileSize;
}

char* getFileContent(FILE* file)
{
    long fileSize = getFileContentSize(file);
    char* contentBuffer = (char*) malloc(fileSize);
    fread(contentBuffer, fileSize, sizeof(char), file);

    return contentBuffer;
}

void navigateDirectory(const char* path, std::vector<std::string>& outFiles)
{
    DIR* directory = opendir(path);
    struct dirent* ent;
    if(directory)
    {
        std::string fullPath = path;
        fullPath += "/";
        outFiles.push_back(fullPath);

        while((ent = readdir(directory)) != NULL)
        {
            std::string fileName = ent->d_name;
            std::string fileNameFullPath = path;
            if(fileName.compare(".") != 0 && fileName.compare("..") != 0)
            {
                fileNameFullPath += "/";
                fileNameFullPath += fileName;

                if(isFile(fileNameFullPath.c_str()))
                {
                    outFiles.push_back(fileNameFullPath);
                }
                else
                {
                    navigateDirectory(fileNameFullPath.c_str(), outFiles);
                }
            }
        }
    }
}

const char* appendSlash(const char* path)
{
    std::string newPath = path;

    if(path[newPath.size() - 1] != '/')
    {
        newPath += '/';
    }

    return newPath.c_str();
}

std::string backToRelativePath(std::string path)
{
    int size = path.size();
    int pos = path.find_last_of("/", size - 2);
    if(pos < 0){
        return path;
    }
    return path.erase(pos);
}